/*--------------------------------------------------------------------------------
 * Adaptive Intelligence - Foundation Framework Class Library
 * Version 2.00
 * 
 * Triple-DES Cryptographic Device Class
 *      Provides a class for performing symmetric encryption using the Triple-DES algorithm.
 *------------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------------
 * System Imports
 *------------------------------------------------------------------------------*/
using System;
using System.IO;
using System.Security;
using System.Security.Cryptography;

namespace Adaptive.Foundation.Security
{
    /// <summary>
    /// Provides a class for performing symmetric encryption using the Triple-DES algorithm.
    /// </summary>
    public class TripleDesCryptoDevice : SymmetricCryptographicDeviceBase
    {
        /*--------------------------------------------------------------------------------
         * Constructor / Dispose / Destructor Methods
         *------------------------------------------------------------------------------*/
        #region Constructor / Dispose / Destructor Methods
        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        /// <remarks>
        /// This is the default constructor.
        /// </remarks>
        public TripleDesCryptoDevice()
            : base()
        {
        }
        /// <summary>
        /// Initializes a new instance of the class to the specified key and IV
        /// values.
        /// </summary>
        /// <param name="key">A byte array containing the AES encryption key.</param>
        /// <param name="iv">A byte array containing the AES initialization vector (IV).</param>
        public TripleDesCryptoDevice(byte[] key, byte[] iv)
        {
            base.Key = key;
            base.IV = iv;
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Public Properties
         *------------------------------------------------------------------------------*/
        #region Public Properties
        /// <summary>
        /// Gets a value indicating whether the current instance can perform
        /// decryption operations.
        /// </summary>
        /// <value>
        /// <b>true</b> if the current instance is in a state where decryption
        /// operations may be performed; otherwise, <b>false</b>.
        /// </value>
        public override bool CanDecrypt
        {
            get
            {
                return ((ValidateIV(IV)) && (ValidateKey(Key)));
            }
        }
        /// <summary>
        /// Gets a value indicating whether the current instance can perform
        /// encryption operations.
        /// </summary>
        /// <value>
        /// <b>true</b> if the current instance is in a state where encryption
        /// operations may be performed; otherwise, <b>false</b>.
        /// </value>
        public override bool CanEncrypt
        {
            get
            {
                return ((ValidateIV(IV)) && (ValidateKey(Key)));
            }
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Protected Methods / Event Methods
         *------------------------------------------------------------------------------*/
        #region Protected Methods / Event Methods
        /// <summary>
        /// Performs decryption of the supplied data.
        /// </summary>
        /// <param name="operation">
        /// A <see cref="CryptographicOperation"/> instance containing the neccessary
        /// information to perform the decryption.
        /// </param>
        /// <returns>
        /// <b>true</b> if the operation completes successfully; otherwise, <b>false</b>.
        /// </returns>
        protected override bool DoDecrypt(CryptographicOperation operation)
        {
            return PerformSymmetricOperation(operation, SafeCreateTripleDes(operation));
        }
        /// <summary>
        /// Performs encryption of the supplied data.
        /// </summary>
        /// <param name="operation">
        /// A <see cref="CryptographicOperation"/> instance containing the neccessary
        /// information to perform the encryption.
        /// </param>
        /// <returns>
        /// <b>true</b> if the operation completes successfully; otherwise, <b>false</b>.
        /// </returns>
        protected override bool DoEncrypt(CryptographicOperation operation)
        {
            return PerformSymmetricOperation(operation, SafeCreateTripleDes(operation));
        }
        /// <summary>
        /// Validates the specified initialization vector (IV) for use by the current
        /// implementation.
        /// </summary>
        /// <param name="keyData">
        /// A byte array containing the data to be validated.
        /// </param>
        /// <returns>
        /// <b>true</b> if the IV data is valid; otherwise, <b>false</b>.
        /// </returns>
        protected override bool ValidateIV(byte[] keyData)
        {
            return ((keyData != null) && (keyData.Length == 8));
        }
        /// <summary>
        /// Validates the specified encryption key for use by the current
        /// implementation.
        /// </summary>
        /// <param name="keyData">
        /// A byte array containing the data to be validated.
        /// </param>
        /// <returns>
        /// <b>true</b> if the key data is valid; otherwise, <b>false</b>.
        /// </returns>
        protected override bool ValidateKey(byte[] keyData)
        {
            return ((keyData != null) && (keyData.Length == 24));
        }
        /// <summary>
        /// Sets the type of algorithm used by this implementation.
        /// </summary>
        protected override void SetAlgorithmType()
        {
            base.Algorithm = CryptographicAlgorithm.TripleDes;
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Private Methods / Functions
         *------------------------------------------------------------------------------*/
        #region Private Methods / Functions
        /// <summary>
        /// Creates and returns an Triple-DES cryptographic object instance.
        /// </summary>
        /// <param name="operation">
        /// The <see cref="CryptographicOperation"/> to be performed, where the result
        /// of the operation is also stored.
        /// </param>
        /// <remarks>
        /// Any exceptions caught here are stored in the <i>operation</i> parameter.
        /// </remarks>
        /// <returns>
        /// A new <see cref="TripleDESCryptoServiceProvider"/> instance, if successful; otherwise, returns <b>null</b>.
        /// </returns>
        private TripleDESCryptoServiceProvider SafeCreateTripleDes(CryptographicOperation operation)
        {
            TripleDESCryptoServiceProvider returnValue = null;         //Return value.
            
            //Try to create the initial stream and associated instances.
            try
            {
                //Set up cryptography.
                returnValue = new TripleDESCryptoServiceProvider();
                returnValue.Key = Key;
                returnValue.IV = IV;
            }
            catch (CryptographicException cryptoEx)
            {
                operation.Result.Success = false;
                operation.Result.ResultType = CryptographicResultType.CryptographicException;
                operation.Result.LastException = cryptoEx;
                returnValue = null;
            }
            catch (Exception ex)
            {
                operation.Result.Success = false;
                operation.Result.ResultType = CryptographicResultType.UnknownException;
                operation.Result.LastException = ex;
                returnValue = null;
            }

            return returnValue;
        }
        #endregion
    }
}
